#pragma once

#include "Page.h"
#include "FileManager.h"
#include <unordered_map>
#include <list>
#include <memory>
#include <mutex>
#include <chrono>
#include <iostream>

namespace MiniDB
{

    enum class ReplacementPolicy
    {
        LRU, // Least Recently Used
        FIFO // First In First Out
    };

    struct CacheStats
    {
        size_t total_requests = 0;
        size_t cache_hits = 0;
        size_t cache_misses = 0;
        size_t pages_read = 0;
        size_t pages_written = 0;
        size_t replacements = 0;

        double getHitRate() const
        {
            return total_requests == 0 ? 0.0 : static_cast<double>(cache_hits) / total_requests;
        }

        void reset()
        {
            total_requests = 0;
            cache_hits = 0;
            cache_misses = 0;
            pages_read = 0;
            pages_written = 0;
            replacements = 0;
        }

        void print() const
        {
            std::cout << "=== Cache Statistics ===" << std::endl;
            std::cout << "Total Requests: " << total_requests << std::endl;
            std::cout << "Cache Hits: " << cache_hits << std::endl;
            std::cout << "Cache Misses: " << cache_misses << std::endl;
            std::cout << "Hit Rate: " << (getHitRate() * 100) << "%" << std::endl;
            std::cout << "Pages Read: " << pages_read << std::endl;
            std::cout << "Pages Written: " << pages_written << std::endl;
            std::cout << "Page Replacements: " << replacements << std::endl;
        }
    };

    class BufferManager
    {
    public:
        BufferManager(size_t buffer_size, ReplacementPolicy policy = ReplacementPolicy::LRU);
        ~BufferManager();

        // Page operations
        std::shared_ptr<Page> getPage(int page_id);
        bool flushPage(int page_id);
        bool flushAll();
        void releasePage(int page_id);

        // Buffer management
        void resize(size_t new_size);
        size_t getBufferSize() const { return buffer_size_; }
        size_t getCurrentSize() const { return buffer_pool_.size(); }

        // Statistics and logging
        const CacheStats &getStats() const { return stats_; }
        void resetStats() { stats_.reset(); }
        void enableLogging(bool enable) { logging_enabled_ = enable; }

        // Policy management
        void setReplacementPolicy(ReplacementPolicy policy);

    private:
        // Frame structure for buffer pool
        struct Frame
        {
            std::shared_ptr<Page> page;
            bool is_valid;
            std::chrono::steady_clock::time_point last_access_time;

            Frame() : page(nullptr), is_valid(false) {}
        };

        // LRU list entry
        struct LRUEntry
        {
            int page_id;
            std::list<int>::iterator position;
        };

        // Private methods
        int findVictimPage();
        void loadPageFromDisk(int page_id);
        void writePageToDisk(int page_id);
        void updateAccessTime(int page_id);
        void logReplacement(int victim_page_id, int new_page_id);

        // Data members
        size_t buffer_size_;
        ReplacementPolicy policy_;
        std::vector<Frame> buffer_pool_;
        std::unordered_map<int, size_t> page_table_;                 // page_id -> frame_index
        std::list<int> lru_list_;                                    // For LRU policy
        std::unordered_map<int, LRUEntry> lru_map_;                  // For LRU policy
        std::list<int> fifo_list_;                                   // For FIFO policy
        std::unordered_map<int, std::list<int>::iterator> fifo_map_; // For FIFO policy

        // File manager for disk I/O
        std::shared_ptr<FileHandle> data_file_;
        std::shared_ptr<FileHandle> index_file_;

        // Statistics and logging
        CacheStats stats_;
        bool logging_enabled_;
        mutable std::mutex mutex_; // Thread safety

        // Constants
        static const std::string DATA_FILE_NAME;
        static const std::string INDEX_FILE_NAME;
    };

} // namespace MiniDB
